﻿using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;

namespace Zhaoxi.NET6.AuthDemo.Utility
{
    /// <summary>
    /// 鉴权Handler
    /// </summary>
    public class UrlTokenAuthenticationHandler : IAuthenticationHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler
    {
        #region Init
        private AuthenticationScheme _AuthenticationScheme = null;//"UrltokenScheme"
        private HttpContext _HttpContext = null;
        /// <summary>
        /// 初始化，Provider传递进来的
        /// 像方法注入
        /// </summary>
        /// <param name="scheme"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
        {
            Console.WriteLine($"This is {nameof(UrlTokenAuthenticationHandler)}.InitializeAsync");
            this._AuthenticationScheme = scheme;
            this._HttpContext = context;
            return Task.CompletedTask;
        }
        #endregion

        /// <summary>
        /// 核心处理方法，完成凭证解析
        /// </summary>
        /// <returns></returns>
        public Task<AuthenticateResult> AuthenticateAsync()
        {
            Console.WriteLine($"This is {nameof(UrlTokenAuthenticationHandler)}.AuthenticateAsync");
            string userInfo = this._HttpContext.Request.Query["UrlToken"];//信息从哪里读
            if (string.IsNullOrWhiteSpace(userInfo))
            {
                return Task.FromResult<AuthenticateResult>(AuthenticateResult.NoResult());
            }
            else if ("eleven-123456".Equals(userInfo))//没去数据库
            {
                //把信息传递下去--让授权去使用--写入context.User
                var claimIdentity = new ClaimsIdentity("Custom");
                claimIdentity.AddClaim(new Claim(ClaimTypes.Name, "Eleven"));
                claimIdentity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
                claimIdentity.AddClaim(new Claim(ClaimTypes.Email, "xuyang@ZhaoxiEdu.Net"));
                claimIdentity.AddClaim(new Claim(ClaimTypes.Country, "China"));
                claimIdentity.AddClaim(new Claim(ClaimTypes.DateOfBirth, "1986"));//识别出来的用户信息
                claimIdentity.AddClaim(new Claim("Student", "Reason"));
                ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimIdentity);//信息拼装和传递

                return Task.FromResult<AuthenticateResult>(AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, null, _AuthenticationScheme.Name)));
            }
            else
            {
                return Task.FromResult<AuthenticateResult>(AuthenticateResult.Fail($"UrlToken is wrong: {userInfo}"));
            }

        }


        /// <summary>
        /// 未登录
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task ChallengeAsync(AuthenticationProperties properties)
        {
            Console.WriteLine($"This is {nameof(UrlTokenAuthenticationHandler)}.ChallengeAsync");
            string redirectUri = "/Auth/Index";
            this._HttpContext.Response.Redirect(redirectUri);
            return Task.CompletedTask;
        }

        /// <summary>
        /// 未授权，无权限
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task ForbidAsync(AuthenticationProperties properties)
        {
            Console.WriteLine($"This is {nameof(UrlTokenAuthenticationHandler)}.ForbidAsync");
            this._HttpContext.Response.StatusCode = 403;
            return Task.CompletedTask;
        }
        /// <summary>
        /// SignInAsync和SignOutAsync使用了独立的定义接口，
        /// 因为在现代架构中，通常会提供一个统一的认证中心，负责证书的颁发及销毁（登入和登出），
        /// 而其它服务只用来验证证书，并用不到SingIn/SingOut。
        /// </summary>
        /// <param name="user"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
        {
            var ticket = new AuthenticationTicket(user, properties, this._AuthenticationScheme.Name);
            this._HttpContext.Response.Cookies.Append("UrlTokenCookie", System.Text.Json.JsonSerializer.Serialize(ticket.Principal.Claims));
            //把一些信息再写入到前端cookie，客户端请求时，从coookie读取UrlTokenCookie信息，放到url上
            return Task.CompletedTask;
        }

        /// <summary>
        /// 退出
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task SignOutAsync(AuthenticationProperties properties)
        {
            this._HttpContext.Response.Cookies.Delete("UrlTokenCookie");
            return Task.CompletedTask;
        }
    }

    public class UrlTokenAuthenticationDefaults
    {
        /// <summary>
        /// 提供固定名称
        /// </summary>
        public const string AuthenticationScheme = "UrlTokenScheme";
    }
}
